package com.scau.jansing.thread.first.queue;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

/**
 * DelayQueue用的是PriorityQueue实现的，
 * 利用PQ来排序，所以队列内的元素需要实现compareTo方法
 * 实现Delayed接口的getDelay方法，来判断，取元素的时候能否取出，如果为空则阻塞
 * 无容量上限
 * Created by jansing on 2016/1/1.
 */
public class LearnDelayQueue {
    public static void main(String[] args) {
        Random random = new Random(47);
        ExecutorService exec = Executors.newCachedThreadPool();
        DelayQueue<DelayedTask> queue = new DelayQueue<>();

        for(int i = 0; i<20; i++){
            queue.put(new DelayedTask(random.nextInt(5000)));
        }
//        最后一个用于结束
        queue.add(new DelayedTask.EndSentinel(5000, exec));
        exec.execute(new DelayedTaskConsumer(queue));
    }

}


//实现Delayed接口，由它判断这个对象是否可以取出
class DelayedTask implements Runnable, Delayed{
    private static int counter = 0;
    private final int id = counter++;
    private final int delta;
    private final long trigger;
    protected static List<DelayedTask> sequence = new ArrayList<>();
    public DelayedTask(int delayInMilliseconds){
        delta = delayInMilliseconds;
//        时间精确到纳秒，
        trigger = System.nanoTime() + TimeUnit.NANOSECONDS.convert(delta, TimeUnit.MILLISECONDS);
        sequence.add(this);
    }
    //Delayed接口方法，用于判断这个对象是否可以取出
    @Override
    public long getDelay(TimeUnit unit){
        return unit.convert(trigger - System.nanoTime(), TimeUnit.NANOSECONDS);
    }
    //用于PriorityQueue排序
    @Override
    public int compareTo(Delayed arg){
        DelayedTask that = (DelayedTask)arg;
        if(trigger < that.trigger){
            return -1;
        }
        if(trigger > that.trigger){
            return 1;
        }
        return 0;
    }
    @Override
    public String toString(){
        return String.format("[%1$4d]", delta) + " Task " +id;
    }
    public String summary(){
        return "(" + id + ":" + delta +")";
    }

    @Override
    public void run() {
        System.out.println(this + " ");
    }

//    最后一个，输出（不是DelayQueue）队列信息并执行exec.shutdownNow
    public static class EndSentinel extends DelayedTask{
        private ExecutorService exec;
        public EndSentinel(int delay, ExecutorService e) {
            super(delay);
            exec = e;
        }
        public void run(){
            for(DelayedTask pt : sequence){
                System.out.println(pt.summary() + " ");
            }
            System.out.println();
            System.out.println(this + " Calling shutdownNow");
            exec.shutdownNow();
        }
    }
}

class DelayedTaskConsumer implements Runnable{
    private DelayQueue<DelayedTask> q;
    public DelayedTaskConsumer(DelayQueue<DelayedTask> q){
        this.q = q;
    }

    @Override
    public void run() {
        try{
            while(!Thread.interrupted()){
                q.take().run();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Finished DelayedTaskConsumer");
    }
}
